/********************************************
 * Version: $Id: rdb.c 11 2010-01-05 08:22:19Z koroharo $
 ********************************************/
#include "jtokyotyrant_jni_RDBJni.h"
#include "myconf.h"


/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBJni_init
  (JNIEnv *env, jclass cls) {
  init_native_rdb_field(env, cls);
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    initialize
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBJni_initialize
  (JNIEnv *env, jobject self) {
  TCRDB *rdb = tcrdbnew();
  set_native_rdb(env, self, rdb);
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    destruct
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBJni_destruct
  (JNIEnv *env, jobject self) {
	TCRDB *rdb = native_rdb(env, self);
	if (rdb) tcrdbdel(rdb);  
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    errmsg
 * Signature: (I)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jtokyotyrant_jni_RDBJni_errmsg
  (JNIEnv *env, jobject self, jint ecode) {
	jstring jmsg;
	jmsg = (*env)->NewStringUTF(env, tcrdberrmsg(ecode));
	if(!jmsg){
		throwoutmem(env, "jstring allocate error");
		return NULL;
	}
	return jmsg;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    ecode
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_jtokyotyrant_jni_RDBJni_ecode
  (JNIEnv *env, jobject self) {
	TCRDB *rdb = native_rdb(env, self);
	return tcrdbecode(rdb);
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    tune
 * Signature: (DI)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_tune
  (JNIEnv *env, jobject self, jdouble timeout, jint opts) {
	TCRDB *rdb = native_rdb(env, self);
	return tcrdbtune(rdb, timeout, opts);
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    open
 * Signature: (Ljava/lang/String;I)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_open__Ljava_lang_String_2I
  (JNIEnv *env, jobject self, jstring jhost, jint jport) {
	if (!jhost) {
		throwillarg(env, "jhost is null");
		return false;
	}

	jboolean ic_host;
	const char *host = (*env)->GetStringUTFChars(env, jhost, &ic_host);
	if (!host) {
		throwoutmem(env, "jhost to char*");
		return false;
	}
	
  	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbopen(rdb, host, jport);
	
	if (ic_host) (*env)->ReleaseStringUTFChars(env, jhost, host); 
  	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    open
 * Signature: (Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_open__Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jexpr) {
	if (!jexpr) {
		throwillarg(env, "jexpr is null");
		return false;
	}

	jboolean ic_expr;
	const char *expr = (*env)->GetStringUTFChars(env, jexpr, &ic_expr);
	if (!expr) {
		throwoutmem(env, "jexpr to char*");
		return false;
	}
	
  	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbopen2(rdb, expr);
	
	if (ic_expr) (*env)->ReleaseStringUTFChars(env, jexpr, expr);
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    close
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_close
  (JNIEnv *env, jobject self) {
	TCRDB *rdb = native_rdb(env, self);
	return tcrdbclose(rdb);
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    put
 * Signature: ([B[B)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_put___3B_3B
  (JNIEnv *env, jobject self, jbyteArray jkey, jbyteArray jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}
	
	jboolean ic_key;
	jsize keysiz = (*env)->GetArrayLength(env, jkey);
	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
	if (!keybuf) {
		throwoutmem(env, "jkey to jbyte*");
		return false;
	}
	
	jboolean ic_value;
	jsize valuesiz = (*env)->GetArrayLength(env, jvalue);
	jbyte *valuebuf = (*env)->GetByteArrayElements(env, jvalue, &ic_value);
	if (!valuebuf) {
		throwoutmem(env, "jvalue to jbyte*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbput(rdb, keybuf, keysiz, valuebuf, valuesiz);
	
	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	if (ic_value) (*env)->ReleaseByteArrayElements(env, jvalue, valuebuf, JNI_ABORT);
		
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    put
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_put__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey, jstring jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	jboolean ic_value;
	const char *value = (*env)->GetStringUTFChars(env, jvalue, &ic_value);
	if (!value) {
		throwoutmem(env, "jvalue to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbput2(rdb, key, value);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	if (ic_value) (*env)->ReleaseStringUTFChars(env, jvalue, value);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putkeep
 * Signature: ([B[B)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putkeep___3B_3B
  (JNIEnv *env, jobject self, jbyteArray jkey, jbyteArray jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

  	jboolean ic_key;
  	jsize keysiz = (*env)->GetArrayLength(env, jkey);
  	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
  	if (!keybuf) {
  		throwoutmem(env, "jkey to jbyte*");
  		return false;
  	}
  	
  	jboolean ic_value;
  	jsize valuesiz = (*env)->GetArrayLength(env, jvalue);
  	jbyte *valuebuf = (*env)->GetByteArrayElements(env, jvalue, &ic_value);
  	if (!valuebuf) {
  		throwoutmem(env, "jvalue to jbyte*");
  		return false;
  	}
  	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputkeep(rdb, keybuf, keysiz, valuebuf, valuesiz);
  	
  	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
  	if (ic_value) (*env)->ReleaseByteArrayElements(env, jvalue, valuebuf, JNI_ABORT);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putkeep
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putkeep__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey, jstring jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	jboolean ic_value;
	const char *value = (*env)->GetStringUTFChars(env, jvalue, &ic_value);
	if (!value) {
		throwoutmem(env, "jvalue to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputkeep2(rdb, key, value);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	if (ic_value) (*env)->ReleaseStringUTFChars(env, jvalue, value);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putcat
 * Signature: ([B[B)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putcat___3B_3B
  (JNIEnv *env, jobject self, jbyteArray jkey, jbyteArray jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

  	jboolean ic_key;
  	jsize keysiz = (*env)->GetArrayLength(env, jkey);
  	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
  	if (!keybuf) {
  		throwoutmem(env, "jkey to jbyte*");
  		return false;
  	}
  	
  	jboolean ic_value;
  	jsize valuesiz = (*env)->GetArrayLength(env, jvalue);
  	jbyte *valuebuf = (*env)->GetByteArrayElements(env, jvalue, &ic_value);
  	if (!valuebuf) {
  		throwoutmem(env, "jvalue to jbyte*");
  		return false;
  	}
  	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputcat(rdb, keybuf, keysiz, valuebuf, valuesiz);
  	
  	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
  	if (ic_value) (*env)->ReleaseByteArrayElements(env, jvalue, valuebuf, JNI_ABORT);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putcat
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putcat__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey, jstring jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	jboolean ic_value;
	const char *value = (*env)->GetStringUTFChars(env, jvalue, &ic_value);
	if (!value) {
		throwoutmem(env, "jvalue to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputcat2(rdb, key, value);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	if (ic_value) (*env)->ReleaseStringUTFChars(env, jvalue, value);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putshl
 * Signature: ([B[BI)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putshl___3B_3BI
  (JNIEnv *env, jobject self, jbyteArray jkey, jbyteArray jvalue, jint jwidth) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

  	jboolean ic_key;
  	jsize keysiz = (*env)->GetArrayLength(env, jkey);
  	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
  	if (!keybuf) {
  		throwoutmem(env, "jkey to jbyte*");
  		return false;
  	}
  	
  	jboolean ic_value;
  	jsize valuesiz = (*env)->GetArrayLength(env, jvalue);
  	jbyte *valuebuf = (*env)->GetByteArrayElements(env, jvalue, &ic_value);
  	if (!valuebuf) {
  		throwoutmem(env, "jvalue to jbyte*");
  		return false;
  	}
  	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputshl(rdb, keybuf, keysiz, valuebuf, valuesiz, jwidth);
  	
  	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
  	if (ic_value) (*env)->ReleaseByteArrayElements(env, jvalue, valuebuf, JNI_ABORT);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putshl
 * Signature: (Ljava/lang/String;Ljava/lang/String;I)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putshl__Ljava_lang_String_2Ljava_lang_String_2I
  (JNIEnv *env, jobject self, jstring jkey, jstring jvalue, jint jwidth) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	jboolean ic_value;
	const char *value = (*env)->GetStringUTFChars(env, jvalue, &ic_value);
	if (!value) {
		throwoutmem(env, "jvalue to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputshl2(rdb, key, value, jwidth);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	if (ic_value) (*env)->ReleaseStringUTFChars(env, jvalue, value);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putnr
 * Signature: ([B[B)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putnr___3B_3B
  (JNIEnv *env, jobject self, jbyteArray jkey, jbyteArray jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

  	jboolean ic_key;
  	jsize keysiz = (*env)->GetArrayLength(env, jkey);
  	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
  	if (!keybuf) {
  		throwoutmem(env, "jkey to jbyte*");
  		return false;
  	}
  	
  	jboolean ic_value;
  	jsize valuesiz = (*env)->GetArrayLength(env, jvalue);
  	jbyte *valuebuf = (*env)->GetByteArrayElements(env, jvalue, &ic_value);
  	if (!valuebuf) {
  		throwoutmem(env, "jvalue to jbyte*");
  		return false;
  	}
  	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputnr(rdb, keybuf, keysiz, valuebuf, valuesiz);
  	
  	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
  	if (ic_value) (*env)->ReleaseByteArrayElements(env, jvalue, valuebuf, JNI_ABORT);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    putnr
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_putnr__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey, jstring jvalue) {
	if (!jkey || !jvalue) {
		throwillarg(env, "jkey or jvalue is null");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	jboolean ic_value;
	const char *value = (*env)->GetStringUTFChars(env, jvalue, &ic_value);
	if (!value) {
		throwoutmem(env, "jvalue to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbputnr2(rdb, key, value);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	if (ic_value) (*env)->ReleaseStringUTFChars(env, jvalue, value);
  	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    out
 * Signature: ([B)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_out___3B
  (JNIEnv *env, jobject self, jbyteArray jkey) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return false;
	}

	jboolean ic_key;
	jsize keysiz = (*env)->GetArrayLength(env, jkey);
	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
	if (!keybuf) {
		throwoutmem(env, "jkey to jbyte");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbout(rdb, keybuf, keysiz);
	
	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    out
 * Signature: (Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_out__Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbout2(rdb, key);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	return result; 
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    get
 * Signature: ([B)[B
 */
JNIEXPORT jbyteArray JNICALL Java_jtokyotyrant_jni_RDBJni_get___3B
  (JNIEnv *env, jobject self, jbyteArray jkey) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return NULL;
	}
	
	jboolean ic_key;
	jsize keysiz = (*env)->GetArrayLength(env, jkey);
	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
	if (!keybuf) {
		throwoutmem(env, "jkey to jbyte");
		return NULL;
	}
	

	TCRDB *rdb = native_rdb(env, self);
	int valuesiz;
	jbyte *valuebuf = tcrdbget(rdb, keybuf, keysiz, &valuesiz);
	jbyteArray jvalue;
	if (valuebuf) {
		jvalue = (*env)->NewByteArray(env, valuesiz); 
		if (!jvalue) {
			throwoutmem(env, "jbyteArray allocate error");
			return NULL;
		}
		(*env)->SetByteArrayRegion(env, jvalue, 0, valuesiz, valuebuf);
		tcfree(valuebuf);
	} else {
		jvalue = NULL;
	}

	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	
	return jvalue;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    get
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jtokyotyrant_jni_RDBJni_get__Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return NULL;
	}
	
	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return NULL;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	char *value = tcrdbget2(rdb, key);

	jstring jvalue;
	if (value) {
		jvalue = (*env)->NewStringUTF(env, value);
		if (!jvalue) {
			throwoutmem(env, "jstring allocate error");
			return NULL;
		}
		tcfree(value);
	} else {
		jvalue = NULL;
	}
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	
	return jvalue;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    mget
 * Signature: (Ljava/util/Map;)I
 */
JNIEXPORT jint JNICALL Java_jtokyotyrant_jni_RDBJni_mget
  (JNIEnv *env, jobject self, jobject jrecs /* Map<byte[], byte[]> */) {
	if (!jrecs) {
		throwillarg(env, "jrecs is null");
		return 0;
	}

	TCMAP *recs = jbytemap2tcmap(env, jrecs);
	if (!recs) {
		throwillsta(env, "jrecs to tcmap");
		return 0;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	if (!tcrdbget3(rdb, recs)) {
		throwillsta(env, "tcrdbget3 fail");
		return 0;
	}
	
	int rnum = tcmaprnum(recs);
	
	if (!puttcmap2jbytemap(recs, env, jrecs)) {
		throwillsta(env, "puttcmap2jbytemap fail");
		return 0;
	}

	tcmapdel(recs);	
	return rnum;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    vsiz
 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_jtokyotyrant_jni_RDBJni_vsiz___3B
  (JNIEnv *env, jobject self, jbyteArray jkey) {
  	if (!jkey) {
  		throwillarg(env, "jkey is null");
  		return 0;
  	}
  
	jboolean ic_key;
	jsize keysiz = (*env)->GetArrayLength(env, jkey);
	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
	if (!keybuf) {
		throwoutmem(env, "jkey to jbyte");
		return 0;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	int result = tcrdbvsiz(rdb, keybuf, keysiz);

	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    vsiz
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_jtokyotyrant_jni_RDBJni_vsiz__Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jkey) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return 0;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return 0;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	int result = tcrdbvsiz2(rdb, key);
	
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
 	return result; 
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    iterinit
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_iterinit
  (JNIEnv *env, jobject self) {
	TCRDB *rdb = native_rdb(env, self);
	return tcrdbiterinit(rdb);
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    iternext
 * Signature: ()[B
 */
JNIEXPORT jbyteArray JNICALL Java_jtokyotyrant_jni_RDBJni_iternext
  (JNIEnv *env, jobject self) {
	TCRDB *rdb = native_rdb(env, self);
	int keysiz;
	jbyte *keybuf = tcrdbiternext(rdb, &keysiz);
	jbyteArray jkey;
	if (keybuf) {
		jkey = (*env)->NewByteArray(env, keysiz);
		if (!jkey) {
			throwoutmem(env, "jbyteArray allocate error");
			return NULL;
		}
		(*env)->SetByteArrayRegion(env, jkey, 0, keysiz, keybuf);
		tcfree(keybuf);
	} else {
		jkey = NULL;
	}
	return jkey;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    iternext2
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jtokyotyrant_jni_RDBJni_iternext2
  (JNIEnv *env, jobject self) {
	TCRDB *rdb = native_rdb(env, self);
	char *key = tcrdbiternext2(rdb);
	jstring jkey;
	if (key) {
		jkey = (*env)->NewStringUTF(env, key);
		if(!jkey){
			throwoutmem(env, "new string allocate error");
			return NULL;
		}
		tcfree(key);
	} else {
		jkey = NULL;
	}
	return jkey;
} 

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    fwmkeys
 * Signature: ([BI)Ljava/util/List;
 */
JNIEXPORT jobject /*List<byte[]>*/ JNICALL Java_jtokyotyrant_jni_RDBJni_fwmkeys___3BI
  (JNIEnv *env, jobject self, jbyteArray jprefix, jint jmax) {
  	if (!jprefix) {
  		throwillarg(env, "jprefix is null");
  		return NULL;
  	}
  
	jboolean ic_prefix;
	jsize prefixsiz = (*env)->GetArrayLength(env, jprefix);
	jbyte *prefixbuf = (*env)->GetByteArrayElements(env, jprefix, &ic_prefix);
	if (!prefixbuf) {
		throwoutmem(env, "jprefix to jbyte");
		return NULL;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	TCLIST *keylist = tcrdbfwmkeys(rdb, prefixbuf, prefixsiz, jmax);
	
	jobject jkeylist = tclist2jbytelist(env, keylist);
	if (!jkeylist) {
		throwillsta(env, "tclist2jbytelist fail");
		return NULL;
	}

	if (ic_prefix) (*env)->ReleaseByteArrayElements(env, jprefix, prefixbuf, JNI_ABORT);
	tclistdel(keylist);
	
	return jkeylist;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    fwmkeys
 * Signature: (Ljava/lang/String;I)Ljava/util/List;
 */
JNIEXPORT jobject /*List<String>*/ JNICALL Java_jtokyotyrant_jni_RDBJni_fwmkeys__Ljava_lang_String_2I
  (JNIEnv *env, jobject self, jstring jprefix, jint jmax) {
  	if (!jprefix) {
  		throwillarg(env, "jprefix is null");
  		return NULL;
  	}
  
	jboolean ic_prefix;
	const char *prefix = (*env)->GetStringUTFChars(env, jprefix, &ic_prefix);
	if (!prefix) {
		throwoutmem(env, "jprefix to char*");
		return NULL;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	TCLIST *keylist = tcrdbfwmkeys2(rdb, prefix, jmax);
	
	jobject jkeylist = tclist2jstrlist(env, keylist);
	if (!jkeylist) {
		throwillsta(env, "tclist2jstrlist fail");
		return NULL;
	}

	if (ic_prefix) (*env)->ReleaseStringUTFChars(env, jprefix, prefix);
	tclistdel(keylist);
	
	return jkeylist;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    addint
 * Signature: ([BI)I
 */
JNIEXPORT jint JNICALL Java_jtokyotyrant_jni_RDBJni_addint
  (JNIEnv *env, jobject self, jbyteArray jkey, jint jnum) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return false;
	}

  	jboolean ic_key;
  	jsize keysiz = (*env)->GetArrayLength(env, jkey);
  	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
  	if (!keybuf) {
  		throwoutmem(env, "jkey to jbyte*");
  		return false;
  	}
	
	TCRDB *rdb = native_rdb(env, self);
	int result = tcrdbaddint(rdb, keybuf, keysiz, jnum);
	
	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    adddouble
 * Signature: ([BD)D
 */
JNIEXPORT jdouble JNICALL Java_jtokyotyrant_jni_RDBJni_adddouble
  (JNIEnv *env, jobject self, jbyteArray jkey, jdouble jnum) {
	if (!jkey) {
		throwillarg(env, "jkey is null");
		return false;
	}

  	jboolean ic_key;
  	jsize keysiz = (*env)->GetArrayLength(env, jkey);
  	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
  	if (!keybuf) {
  		throwoutmem(env, "jkey to jbyte*");
  		return false;
  	}
	
	TCRDB *rdb = native_rdb(env, self);
	int result = tcrdbadddouble(rdb, keybuf, keysiz, jnum);
	
	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    ext
 * Signature: (Ljava/lang/String;[B[BI)[B
 */
JNIEXPORT jbyteArray JNICALL Java_jtokyotyrant_jni_RDBJni_ext
  (JNIEnv *env, jobject self, jstring jname, jbyteArray jkey, jbyteArray jvalue, jint jopts) {
	if (!jname || !jkey || !jvalue) {
		throwillarg(env, "jname or jkey or jvalue is null");
		return false;
	}
	
	jboolean ic_name;
	const char *name = (*env)->GetStringUTFChars(env, jname, &ic_name);
	if (!name) {
		throwoutmem(env, "jname to char*");
		return false;
	}

	jboolean ic_key;
	jsize keysiz = (*env)->GetArrayLength(env, jkey);
	jbyte *keybuf = (*env)->GetByteArrayElements(env, jkey, &ic_key);
	if (!keybuf) {
		throwoutmem(env, "jkey to jbyte*");
		return false;
	}
	
	jboolean ic_value;
	jsize valuesiz = (*env)->GetArrayLength(env, jvalue);
	jbyte *valuebuf = (*env)->GetByteArrayElements(env, jvalue, &ic_value);
	if (!valuebuf) {
		throwoutmem(env, "jvalue to jbyte*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	int resultsiz;
	jbyte *result = tcrdbext(rdb, name, jopts, keybuf, keysiz, valuebuf, valuesiz, &resultsiz);
	if (!result) {
		char msg[64];
		snprintf(msg, sizeof(msg), "tcrdbext failed: %s", name);
		throwillsta(env, msg);
		return NULL;
	}
	
	jbyteArray jresult = (*env)->NewByteArray(env, resultsiz);
	if (!jresult) {
		throwoutmem(env, "jbyteArray allocate error");
		return NULL;
	}
	(*env)->SetByteArrayRegion(env, jresult, 0, resultsiz, result);
	
	if (ic_name) (*env)->ReleaseStringUTFChars(env, jname, name);
	if (ic_key) (*env)->ReleaseByteArrayElements(env, jkey, keybuf, JNI_ABORT);
	if (ic_value) (*env)->ReleaseByteArrayElements(env, jvalue, valuebuf, JNI_ABORT);
	tcfree(result);
		
	return jresult;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    ext2
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jtokyotyrant_jni_RDBJni_ext2
  (JNIEnv *env, jobject self, jstring jname, jstring jkey, jstring jvalue, jint jopts) {
	if (!jname || !jkey || !jvalue) {
		throwillarg(env, "jname or jkey or jvalue is null");
		return false;
	}

	jboolean ic_name;
	const char *name = (*env)->GetStringUTFChars(env, jname, &ic_name);
	if (!name) {
		throwoutmem(env, "jname to char*");
		return false;
	}

	jboolean ic_key;
	const char *key = (*env)->GetStringUTFChars(env, jkey, &ic_key);
	if (!key) {
		throwoutmem(env, "jkey to char*");
		return false;
	}
	
	jboolean ic_value;
	const char *value = (*env)->GetStringUTFChars(env, jvalue, &ic_value);
	if (!value) {
		throwoutmem(env, "jvalue to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	char *result = tcrdbext2(rdb, name, jopts, key, value);
	if (!result) {
		char msg[64];
		snprintf(msg, sizeof(msg), "tcrdbext2 failed: %s", name);
		throwillsta(env, msg);
		return NULL;
	}
	
	jstring jresult = (*env)->NewStringUTF(env, result);
	if (!jresult) {
		throwoutmem(env, "jstring allocate error");
		return NULL;
	}

	if (ic_name) (*env)->ReleaseStringUTFChars(env, jname, name);
	if (ic_key) (*env)->ReleaseStringUTFChars(env, jkey, key);
	if (ic_value) (*env)->ReleaseStringUTFChars(env, jvalue, value);
	tcfree(result);
	
	return jresult;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    sync
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_sync
  (JNIEnv *env, jobject self) {
	return tcrdbsync(native_rdb(env, self));
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    optimize
 * Signature: (Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_optimize
  (JNIEnv *env, jobject self, jstring jparams) {
	jboolean ic_params;
	const char *params;
	if (jparams) {
		params = (*env)->GetStringUTFChars(env, jparams, &ic_params);
		if (!params) {
			throwoutmem(env, "jparams to char*");
			return false;
		}
	} else {
		ic_params = false;
		params = NULL;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdboptimize(rdb, params);
	
	if (ic_params) (*env)->ReleaseStringUTFChars(env, jparams, params);
	
	return result;
	 
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    vanish
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_vanish
  (JNIEnv *env, jobject self) {
	return tcrdbvanish(native_rdb(env, self)); 
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    copy
 * Signature: (Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_copy
  (JNIEnv *env, jobject self, jstring jpath) {
	if (!jpath) {
		throwillarg(env, "jpath is null");
		return false;
	}
	
	jboolean ic_path;
	const char *path = (*env)->GetStringUTFChars(env, jpath, &ic_path);
	if (!path) {
		throwoutmem(env, "jpath to char*");
		return false;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbcopy(rdb, path);
	
	if (ic_path) (*env)->ReleaseStringUTFChars(env, jpath, path);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    restore
 * Signature: (Ljava/lang/String;JI)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_restore
  (JNIEnv *env, jobject self, jstring jpath, jlong jtimeout, jint jopts) {
	if (!jpath) {
		throwillarg(env, "jpath is null");
		return false;
	}
	
	jboolean ic_path;
	const char *path = (*env)->GetStringUTFChars(env, jpath, &ic_path);
	if (!path) {
		throwoutmem(env, "jpath to char*");
		return false;
	}

	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbrestore(rdb, path, jtimeout, jopts);

	if (ic_path) (*env)->ReleaseStringUTFChars(env, jpath, path);
	
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    setmst
 * Signature: (Ljava/lang/String;IJI)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_setmst__Ljava_lang_String_2IJI
  (JNIEnv *env, jobject self, jstring jhost, jint jport, jlong jts, jint jopts) {
	if (!jhost) {
		throwillarg(env, "jhost is null");
		return false;
	}

	jboolean ic_host;
	const char *host = (*env)->GetStringUTFChars(env, jhost, &ic_host);
	if (!host) {
		throwoutmem(env, "jhost to char*");
		return false;
	}
	
  	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbsetmst(rdb, host, jport, jts, jopts);
	
	if (ic_host) (*env)->ReleaseStringUTFChars(env, jhost, host); 

  	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    setmst
 * Signature: (Ljava/lang/String;JI)Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBJni_setmst__Ljava_lang_String_2JI
  (JNIEnv *env, jobject self, jstring jexpr, jlong jts, jint jopts) {
	if (!jexpr) {
		throwillarg(env, "jexpr is null");
		return false;
	}

	jboolean ic_expr;
	const char *expr = (*env)->GetStringUTFChars(env, jexpr, &ic_expr);
	if (!expr) {
		throwoutmem(env, "jexpr to char*");
		return false;
	}
	
  	TCRDB *rdb = native_rdb(env, self);
	bool result = tcrdbsetmst2(rdb, expr, jts, jopts);
	
	if (ic_expr) (*env)->ReleaseStringUTFChars(env, jexpr, expr);
	return result;
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    rnum
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_jtokyotyrant_jni_RDBJni_rnum
  (JNIEnv *env, jobject self) {
	return tcrdbrnum(native_rdb(env, self));
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    size
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_jtokyotyrant_jni_RDBJni_size
  (JNIEnv *env, jobject self) {
	return tcrdbsize(native_rdb(env, self));
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    stat
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jtokyotyrant_jni_RDBJni_stat
  (JNIEnv *env, jobject self) {
	char *stat = tcrdbstat(native_rdb(env, self));
	if (stat) {
		jstring result = (*env)->NewStringUTF(env, stat);
		if (!result) {
			throwoutmem(env, "jstring allocate error");
			return NULL;
		}
	
		tcfree(stat);
		return result;
	} else {
		return NULL;	
	}
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    misc
 * Signature: (Ljava/lang/String;I[[B)Ljava/util/List;
 */
JNIEXPORT jobject /*List<byte[]>*/ JNICALL Java_jtokyotyrant_jni_RDBJni_misc__Ljava_lang_String_2I_3_3B
  (JNIEnv *env, jobject self, jstring jname, jint jopts, jobjectArray jargs /* byte[][] */) {
	if (!jname || !jargs) {
		throwillarg(env, "jname or jargs is null");
		return false;
	}

	jboolean ic_name;
	const char *name = (*env)->GetStringUTFChars(env, jname, &ic_name);
	if (!name) {
		throwoutmem(env, "jname to char*");
		return false;
	}
	
	TCLIST *args = jbytearr2tclist(env, jargs);
	if (!args) {
		throwillsta(env, "jbytearr2tclist fail");
		return NULL;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	TCLIST *result = tcrdbmisc(rdb, name, jopts, args);
	if (!result) {
		throwoutmem(env, "tcrdbmisc fail");
		return NULL;
	}
	
	jobject jresult = tclist2jbytelist(env, result);
	if (!jresult) {
		throwillsta(env, "tclist2jbytelist fail");
		return NULL;
	}
	
	if (ic_name) (*env)->ReleaseStringUTFChars(env, jname, name); 
	tclistdel(args);
	tclistdel(result);
 	return jresult; 
}

/*
 * Class:     jtokyotyrant_jni_RDBJni
 * Method:    misc
 * Signature: (Ljava/lang/String;I[Ljava/lang/String;)Ljava/util/List;
 */
JNIEXPORT jobject /*List<String>*/ JNICALL Java_jtokyotyrant_jni_RDBJni_misc__Ljava_lang_String_2I_3Ljava_lang_String_2
  (JNIEnv *env, jobject self, jstring jname, jint jopts, jobjectArray jargs /* String[] */) {
	if (!jname || !jargs) {
		throwillarg(env, "jname or jargs is null");
		return false;
	}

	jboolean ic_name;
	const char *name = (*env)->GetStringUTFChars(env, jname, &ic_name);
	if (!name) {
		throwoutmem(env, "jname to char*");
		return false;
	}
	
	TCLIST *args = jstrarr2tclist(env, jargs);
	if (!args) {
		throwillsta(env, "jstrarr2tclist fail");
		return NULL;
	}
	
	TCRDB *rdb = native_rdb(env, self);
	TCLIST *result = tcrdbmisc(rdb, name, jopts, args);
	if (!result) {
		throwoutmem(env, "tcrdbmisc fail");
		return NULL;
	}
	
	jobject jresult = tclist2jstrlist(env, result);
	if (!jresult) {
		throwillsta(env, "tclist2jstrlist fail");
		return NULL;
	}
	
	if (ic_name) (*env)->ReleaseStringUTFChars(env, jname, name); 
	tclistdel(args);
	tclistdel(result);
 	return jresult; 
}

